package com.github.data_manage.util

import org.slf4j.LoggerFactory
import java.math.BigDecimal
import java.math.MathContext
import java.math.RoundingMode
import kotlin.math.pow
import kotlin.math.sqrt

/**
 * @author chenhainan
 * @since 2024-08-14 15:20
 */
object DataUtils {

    private val logger = LoggerFactory.getLogger(DataUtils::class.java)

    /**
     * 年初至今收益率
     */
    fun Collection<BigDecimal>.ytd(divide100: Boolean = false): BigDecimal? {
        if (this.isEmpty()) {
            return null
        }
        return this.map { if (divide100) it.divide(BigDecimal.valueOf(100), 10, RoundingMode.HALF_UP) else it }
            .map { it.add(BigDecimal.ONE) }.reduce { a, b -> a * b }.subtract(BigDecimal.ONE)
            .multiply(BigDecimal.valueOf(100))
            .setScale(2, RoundingMode.HALF_UP)
    }


    /**
     * 回报率
     */
    fun Collection<BigDecimal>.nav(): BigDecimal {
        if (this.isEmpty()) {
            return BigDecimal.ZERO
        }
        // 输入校验：确保所有收益率 > -100%（避免乘积为非正数导致后续计算异常）
        val minValidRate = BigDecimal("-1.0")
        for (rate in this) {
            if (rate.compareTo(minValidRate) <= 0) {
                throw IllegalArgumentException("收益率不能小于或等于-100%，当前值: $rate")
            }
        }
        return this.map { it.add(BigDecimal.ONE) }
            .reduce { a, b -> a.multiply(b) }
            .setScale(4, RoundingMode.HALF_UP)
            .toDouble()
            .pow(12.0 / this.size)
            .toBigDecimal()
            .subtract(BigDecimal.ONE)
            .multiply(BigDecimal.valueOf(100))
            .setScale(2, RoundingMode.HALF_UP)
    }

    fun Collection<BigDecimal?>.avg(): BigDecimal {
        if (this.isEmpty()) {
            return BigDecimal.ZERO
        }
        val notNullList = this.filterNotNull()
        return notNullList.sumOf { it }.divide(BigDecimal(notNullList.size), 4, RoundingMode.HALF_UP)
    }

    /**
     * 标准差
     */
    fun Collection<BigDecimal>.standardDeviation(divide100: Boolean = false): BigDecimal {
        if (this.size < 2) return BigDecimal.ZERO // 需要至少2个数据点计算方差
        val realThis = this.map { if (divide100) it.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP) else it }
        val mean = realThis.avg()
        val monthlyStandardDeviation =
            realThis.map { (it - mean).pow(2) }.reduce { a, b -> a.add(b) }
                .divide((realThis.size - 1).toBigDecimal(), 10, RoundingMode.HALF_UP)
                .sqrt(MathContext(10, RoundingMode.HALF_UP))
        return monthlyStandardDeviation.multiply(BigDecimal.valueOf(sqrt(12.0)))
            .multiply(BigDecimal.valueOf(100))
            .setScale(2, RoundingMode.HALF_UP)
    }

    /**
     * 皮尔逊相关系数
     */
    fun pearsonCorrelation(
        returnDataOne: List<BigDecimal>?,
        returnDataTwo: List<BigDecimal>?
    ): BigDecimal? {
        // 添加null检查
        if (returnDataOne == null || returnDataTwo == null) {
            return null
        }

        // 检查列表大小
        if (returnDataOne.isEmpty() || returnDataOne.size != returnDataTwo.size) {
            return null
        }

        // 使用BigDecimal进行计算以避免精度损失
        val n = BigDecimal.valueOf(returnDataOne.size.toLong())

        val sumX = returnDataOne.sumOf { it }
        val sumY = returnDataTwo.sumOf { it }

        val sumXSquared = returnDataOne.sumOf { it * it }
        val sumYSquared = returnDataTwo.sumOf { it * it }

        val sumXY = returnDataOne.zip(returnDataTwo).sumOf { (a, b) -> a * b }

        // 计算分子
        val numerator = sumXY - (sumX * sumY.divide(n, 4, RoundingMode.HALF_UP))

        // 计算分母
        val denominatorX = sqrt((sumXSquared - (sumX * sumX.divide(n, 4, RoundingMode.HALF_UP))).toDouble())
        val denominatorY = sqrt((sumYSquared - (sumY * sumY.divide(n, 4, RoundingMode.HALF_UP))).toDouble())

        // 处理分母为零的情况
        if (denominatorX == 0.0 || denominatorY == 0.0) {
            return null
        }

        val denominator = BigDecimal.valueOf(denominatorX * denominatorY)

        // 计算结果
        val result = numerator.divide(denominator, 4, RoundingMode.HALF_UP)

        // 设置精度
        return result.setScale(4, RoundingMode.HALF_UP)
    }

    /**
     * 计算两组数据的线性回归率
     */
    fun slope(
        x: List<BigDecimal>,
        y: List<BigDecimal>
    ): BigDecimal? {
        if (x.isEmpty() || y.isEmpty() || (x.size != y.size)) {
            return null
        }
        val n = BigDecimal.valueOf(y.size.toLong())

        // Calculate sums
        val sumY = y.sumOf { it }
        val sumX = x.sumOf { it }

        // Calculate sum of products
        val sumXY = y.zip(x).sumOf { (y, x) -> y * x }

        // Calculate sum of squares
        val sumX2 = x.sumOf { it * it }

        // Calculate numerator and denominator for slope formula
        val numerator = n * sumXY - sumX * sumY
        val denominator = n * sumX2 - sumX * sumX

        // Handle division by zero
        if (denominator == BigDecimal.ZERO) {
            return BigDecimal.ZERO
        }

        // Calculate and return slope
        return numerator.divide(denominator, 10, RoundingMode.HALF_UP)
    }

    /**
     * 根据数据大小判断数据位置
     */
    fun indexOfNumberBySize(
        value: BigDecimal,
        values: List<BigDecimal>
    ): Int {
        val newList = ArrayList(values).sorted()
        var index = 0;
        for (decimal in newList) {
            if (value.compareTo(decimal) >= 0) {
                return index
            }
            index++
        }
        return -1
    }


}


